package com.punai.customer.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageInfo;
import com.punai.common.core.page.TableDataInfo;
import com.punai.common.exception.ServiceException;
import com.punai.common.utils.PageUtils;
import com.punai.common.utils.ParseContentUtil;
import com.punai.common.utils.SecurityUtils;
import com.punai.common.utils.StringUtils;
import com.punai.customer.domain.*;
import com.punai.customer.domain.bo.*;
import com.punai.customer.domain.contants.CusConstants;
import com.punai.customer.domain.request.CusRewriteCodeRequest;
import com.punai.customer.domain.vo.*;
import com.punai.customer.mapper.*;
import com.punai.customer.service.ICusFbFeeService;
import com.punai.standard.domain.StaFbFee;
import com.punai.standard.domain.StaGxFee;
import com.punai.standard.domain.StaVersion;
import com.punai.standard.domain.constants.StaConstants;
import com.punai.standard.mapper.StaFbChapterMapper;
import com.punai.standard.mapper.StaFbFeeMapper;
import com.punai.standard.mapper.StaGxFeeMapper;
import com.punai.standard.mapper.StaVersionMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 分包费用项Service业务层处理
 *
 * @author zxw
 * @date 2022-12-09
 */
@Service
public class CusFbFeeServiceImpl extends ServiceImpl<CusFbFeeMapper, CusFbFee> implements ICusFbFeeService
{
    @Autowired
    private CusFbFeeMapper dmcFbFeeMapper;
    @Autowired
    private CusFbChapterMapper cusFbChapterMapper;
    @Autowired
    private CusFeatureMapper cusFeatureMapper;
    @Autowired
    private CusLinkFbFeatureMapper cusLinkFbFeatureMapper;

    @Autowired
    private CusGxFeeMapper cusGxFeeMapper;
    @Autowired
    private CusLinkFeatureMapper cusLinkFeatureMapper;
    @Autowired
    private CusLinkFbGxMapper cusLinkFbGxMapper;
    @Autowired
    private CusExpenseCategoriesMapper cusExpenseCategoriesMapper;
    @Autowired
    private StaGxFeeMapper staGxFeeMapper;
    @Autowired
    private StaVersionMapper staVersionMapper;
    @Autowired
    private CusVersionsDiscrepancyMapper cusVersionsDiscrepancyMapper;
    @Autowired
    private StaFbChapterMapper staFbChapterMapper;
    @Autowired
    private StaFbFeeMapper staFbFeeMapper;
    /**
     * 查询分包费用项
     *
     * @param id 分包费用项主键
     * @param companyId
     * @return 分包费用项
     */
    @Override
    public MergeGxToFeeResultBo selectDmcFbFeeById(String id, Long companyId)
    {
        MergeGxToFeeResultBo resultBo = new MergeGxToFeeResultBo();
        // 获取基础信息
        CusFbFee fee = getById(id, companyId);
        resultBo.setId(fee.getId());
        resultBo.setCompanyId(fee.getCompanyId());
        resultBo.setChapterId(fee.getChapterId());
        resultBo.setCode(fee.getCode());
        resultBo.setName(fee.getName());
        resultBo.setUnit(fee.getUnit());
        resultBo.setContent(fee.getContent());
        resultBo.setCalcRule(fee.getCalcRule());
        resultBo.setOrderNum(fee.getOrderNum());

        // 拿到关联的工序id
        List<CusLinkFbGx> linkFbGxes = cusLinkFbGxMapper.selectList(Wrappers.<CusLinkFbGx>lambdaQuery()
                .eq(CusLinkFbGx::getCompanyId, companyId)
                .eq(CusLinkFbGx::getFbId, id)
                .orderByAsc(CusLinkFbGx::getSort)
        );

        List<String> gxIdList = linkFbGxes.stream().map(CusLinkFbGx::getGxId).collect(Collectors.toList());

        LambdaQueryWrapper<StaVersion> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StaVersion::getCompanyId,companyId);
        wrapper.eq(StaVersion::getType, StaConstants.GX_TYPE);
        wrapper.eq(StaVersion::getSpecId,fee.getSpecId());
        wrapper.orderByDesc(StaVersion::getCreateTime);
        wrapper.last("limit 1");
        StaVersion staVersion = staVersionMapper.selectOne(wrapper);
        if(staVersion == null){
            throw new ServiceException("千年难遇的数据问题，请联系管理员");
        }
        String versionId = staVersion.getId();

        if (CollUtil.isNotEmpty(gxIdList)) {
            List<StaGxFee> staGxFees = staGxFeeMapper.selectList(Wrappers.<StaGxFee>lambdaQuery()
                    .eq(StaGxFee::getVersionId, versionId).in(StaGxFee::getId, gxIdList));

            Map<String, StaGxFee> gxMap = staGxFees.stream().collect(Collectors.toMap(StaGxFee::getId, Function.identity()));

            Map<String, List<String>> fbContent = ParseContentUtil.getContentObj();
            List<GxFeeBo> gxFeeList = new ArrayList<>();
            for (CusLinkFbGx linkFbGx : linkFbGxes) {
                GxFeeBo gxFeeBo = new GxFeeBo();
                StaGxFee gxFee = gxMap.get(linkFbGx.getGxId());
                gxFeeBo.setId(gxFee.getId());
                gxFeeBo.setVersionId(gxFee.getVersionId());
                gxFeeBo.setName(gxFee.getName());
                gxFeeBo.setUnit(gxFee.getUnit());
                gxFeeBo.setSuitableRange(gxFee.getSuitableRange());
                gxFeeBo.setLinkId(linkFbGx.getId());
                gxFeeBo.setEnable(linkFbGx.getEnable());
                gxFeeBo.setOrderNum(linkFbGx.getSort());
                gxFeeList.add(gxFeeBo);
                //去重合并
                ParseContentUtil.mergeContent(fbContent, gxFee.getContent());
            }
            //补充工作内容
            ParseContentUtil.mergeContent(fbContent, fee.getContent());

            resultBo.setGxFeeList(gxFeeList);
            resultBo.setContentJoint(ParseContentUtil.parseContent(fbContent));

            // 材机分类
            List<String> cjflGxIdList = linkFbGxes.stream().filter(e->CusConstants.ENABLE_Y_TYPE.equals(e.getEnable())).map(CusLinkFbGx::getGxId).collect(Collectors.toList());

            List<CusCategoryBo> cusCategoryBos = cusExpenseCategoriesMapper.selectGxFbLinkDataAndEntitySta(companyId,versionId,cjflGxIdList);

            ArrayList<CusCategoryBo> cusCategoryBoList = cusCategoryBos.stream().collect(Collectors.collectingAndThen(
                    Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(CusCategoryBo::getId))), ArrayList::new));

            if (CollUtil.isNotEmpty(cusCategoryBoList)) {
                List<CJFlRes> cjFlRes = new ArrayList<>();
                gxMap.forEach((k,v) -> {
                    List<CusCategoryBo> collect = cusCategoryBoList.stream().filter(e -> k.equals(e.getSubpkId())).collect(Collectors.toList());
                    if (CollUtil.isNotEmpty(collect)) {
                        for (CusCategoryBo cusCategoryBo : collect) {
                            CJFlRes cjfl = new CJFlRes();
                            cjfl.setName(cusCategoryBo.getCategoriesName());
                            cjfl.setUnit(cusCategoryBo.getUnit());
                            cjfl.setSpec(cusCategoryBo.getSpec());
                            cjfl.setType(cusCategoryBo.getType());
                            cjfl.setConsumption(cusCategoryBo.getConsumption());
                            cjFlRes.add(cjfl);
                        }
                    }
                });
                resultBo.setCjflList(cjFlRes);
            }
        }
        // 特征
        // List<CusFeatureBo> cusFeatureBos = cusLinkFbFeatureMapper.selectLinkDataAndEntity(companyId,new String[]{id});
        List<CusFeatureBo> cusFeatureBos = cusLinkFbFeatureMapper.selectLinkFeatureSta(companyId,versionId,gxIdList,CusConstants.GX_TYPE);

        ArrayList<CusFeatureBo> cusFeatureBoList = cusFeatureBos.stream().collect(Collectors.collectingAndThen(
                Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(CusFeatureBo::getId))), ArrayList::new));

        List<FeatureRes> featureResList = new ArrayList<>();
        if (CollUtil.isNotEmpty(cusFeatureBoList)) {
            for (CusFeatureBo cusFeatureBo : cusFeatureBoList) {
                FeatureRes featureRes = new FeatureRes();
                featureRes.setLinkId(cusFeatureBo.getLinkId());
                featureRes.setFeatureId(cusFeatureBo.getId());
                featureRes.setFeatureName(cusFeatureBo.getFeatureName());
                String featureValues = cusFeatureBo.getFeatureValues();
                if (StrUtil.isNotEmpty(featureValues)) {
                    featureValues.replaceAll("|","，");
                }
                featureRes.setInputEntry(cusFeatureBo.getIsInput());
                featureRes.setDefValue(featureValues);
                featureResList.add(featureRes);
            }
        }
        resultBo.setFeatureResList(featureResList);

        return resultBo;
    }

    /**
     * 查询分包费用项列表
     *
     * @param fbFee 分包费用项
     * @param companyId
     * @return 分包费用项
     */
    @Override
    public TableDataInfo selectDmcFbFeeList(CusFbFee fbFee, Long companyId)
    {
        String chapterId = fbFee.getChapterId();
        List<String> chapterIds = new ArrayList<>();

        if(!StringUtils.equals(chapterId,CusConstants.CHAPTER_ID_NULL)){
            chapterIds = cusFbChapterMapper.selectChildrenIdById(chapterId, companyId);
        }else {
            if (StrUtil.isEmpty(fbFee.getSpecId())) {
                throw new RuntimeException("专业获取失败");
            }
        }
        chapterIds.add(0, chapterId);

        PageUtils.startPage();
        List<CusFbFee> cusFbFees = dmcFbFeeMapper.selectCusFbFeeList(fbFee, chapterIds, companyId);
        if (CollUtil.isEmpty(cusFbFees)) {
            return new TableDataInfo(cusFbFees,0);
        }
        Long total = new PageInfo(cusFbFees).getTotal();
        // fixme 可优化的特征查询路径


        // 处理工作内容
        List<String> fbIds = cusFbFees.stream().map(CusFbFee::getId).collect(Collectors.toList());
        List<CusLinkFbGx> cusLinkFbGxes = cusLinkFbGxMapper.selectList(
                Wrappers.<CusLinkFbGx>lambdaQuery()
                        .eq(CusLinkFbGx::getCompanyId, companyId)
                        .in(CusLinkFbGx::getFbId, fbIds)
                        .orderByAsc(CusLinkFbGx::getSort)
        );

        List<String> gxIds = cusLinkFbGxes.stream().map(CusLinkFbGx::getGxId).collect(Collectors.toList());

        LambdaQueryWrapper<StaVersion> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StaVersion::getCompanyId,companyId);
        wrapper.eq(StaVersion::getType, StaConstants.GX_TYPE);
        wrapper.eq(StaVersion::getSpecId,fbFee.getSpecId());
        wrapper.orderByDesc(StaVersion::getCreateTime);
        wrapper.last("limit 1");
        StaVersion staVersion = staVersionMapper.selectOne(wrapper);
        if(staVersion == null){
            throw new ServiceException("千年难遇的BUG，请联系管理员");
        }
        String versionId = staVersion.getId();

        Map<String,StaGxFee> cusGxFeeMap = new HashMap<>();
        if (CollUtil.isNotEmpty(gxIds)) {
            List<StaGxFee> gxFees = staGxFeeMapper.selectList(
                    Wrappers.<StaGxFee>lambdaQuery()
                            .eq(StaGxFee::getVersionId, versionId)
                            .in(StaGxFee::getId, gxIds)
            );
            for (StaGxFee gxFee : gxFees) {
                cusGxFeeMap.put(gxFee.getId(),gxFee);
            }
        }


        Map<String, List<CusLinkFbGx>> linkFbGxMap = cusLinkFbGxes.stream().collect(Collectors.groupingBy(CusLinkFbGx::getFbId));

        for (CusFbFee fee : cusFbFees) {
            String feeId = fee.getId();
            List<CusLinkFbGx> linkFbGxs = linkFbGxMap.get(feeId);

            List<CusLinkFbGx> linkFbGxsSort = linkFbGxs.stream().sorted((e1, e2) -> (int) (e1.getSort() - e2.getSort())).collect(Collectors.toList());

            //分包选择的
            List<String> subGxIds = new ArrayList<>();
            List<String> subRange = new ArrayList<>();
            Map<String, List<String>> fbContent = ParseContentUtil.getContentObj();

            Map<String, StaGxFee> gxMap = new HashMap<>();
            for (CusLinkFbGx linkFbGx : linkFbGxsSort) {
                subGxIds.add(linkFbGx.getGxId());
                StaGxFee gxFee = cusGxFeeMap.get(linkFbGx.getGxId());
                if (gxFee != null) {
                    gxMap.put(gxFee.getId(),gxFee);
                    subRange.add(gxFee.getSuitableRange());
                    //合并工作内容
                    ParseContentUtil.mergeContent(fbContent, gxFee.getContent());
                }
            }
            //补充工作内容
            ParseContentUtil.mergeContent(fbContent, fee.getContent());
            fee.setContent(ParseContentUtil.parseContent(fbContent));
            fee.setSuitableRange(StrUtil.join("；", subRange));

            List<CusFeatureBo> cusFeatureBos = cusLinkFbFeatureMapper.selectLinkFeatureSta(companyId,versionId, subGxIds,CusConstants.GX_TYPE);

            ArrayList<CusFeatureBo> cusFeatureBoList = cusFeatureBos.stream().collect(Collectors.collectingAndThen(
                    Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(CusFeatureBo::getId))), ArrayList::new));

            if (CollUtil.isNotEmpty(cusFeatureBoList)) {
                String featureValues = cusFeatureBoList.stream().distinct().map(CusFeature::getFeatureName).collect(Collectors.joining("；"));
                fee.setFeatureValues(featureValues);
            }


            // 查询材机类别
            List<CusCategoryBo> cusCategoryBos = cusExpenseCategoriesMapper.selectGxFbLinkDataAndEntitySta(companyId,versionId,gxIds);


            ArrayList<CusCategoryBo> cusCategoryBoList = cusCategoryBos.stream().collect(Collectors.collectingAndThen(
                    Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(CusCategoryBo::getId))), ArrayList::new));

            if (CollUtil.isNotEmpty(cusCategoryBoList)) {
                List<CusFbCategoryBo> categoryBos = new ArrayList<>();
                gxMap.forEach((k,v) -> {
                    List<CusCategoryBo> collect = cusCategoryBoList.stream().filter(e -> k.equals(e.getSubpkId())).collect(Collectors.toList());
                    if (CollUtil.isNotEmpty(collect)) {
                        for (CusCategoryBo cusCategoryBo : collect) {
                            CusFbCategoryBo cusFbCategoryBo = new CusFbCategoryBo();
                            cusFbCategoryBo.setCategoryName(cusCategoryBo.getCategoriesName());
                            cusFbCategoryBo.setSpec(cusCategoryBo.getSpec());
                            cusFbCategoryBo.setUnit(cusCategoryBo.getUnit());
                            cusFbCategoryBo.setType(cusCategoryBo.getType());
                            categoryBos.add(cusFbCategoryBo);
                        }
                    }
                });
                fee.setCategoryBos(categoryBos);
            }
        }
        return new TableDataInfo(cusFbFees,total.intValue());
    }

    /**
     * 新增分包费用项
     *
     * @param dmcFbFee 分包费用项
     * @return 结果
     */
    @Override
    public int insertDmcFbFee(CusFbFee dmcFbFee)
    {
            return dmcFbFeeMapper.insert(dmcFbFee);
    }

    /**
     * 修改分包费用项
     *
     * @param vo 分包费用项更新vo
     * @return 结果
     */
    @Override
    @Transactional
    public int updateDmcFbFee(FbFeeUpdateVo vo,Long companyId)
    {
        BasicInfoVo basicInfo = vo.getBasicInfo();
        List<FeatureInfoVo> featureInfo = vo.getFeatureInfo();
        List<String> checkedGxIds = vo.getCheckedGxIds();

        String id = basicInfo.getId();
        // 处理关联的工序
        // 禁用所有
        cusLinkFbGxMapper.disableItem(id,companyId);
        // 启用勾选的
        cusLinkFbGxMapper.enableItem(id,checkedGxIds,companyId);


        // 删除其他特征
        cusLinkFbFeatureMapper.delete(Wrappers.<CusLinkFbFeature>lambdaQuery()
            .eq(CusLinkFbFeature::getItemId,id)
                .eq(CusLinkFbFeature::getCompanyId,companyId)
        );

        // 重新生成特征
        for (FeatureInfoVo featureInfoVo : featureInfo) {
            CusLinkFbFeature linkFbFeature = new CusLinkFbFeature();
            String featureId = featureInfoVo.getFeatureId();
            linkFbFeature.setFeatureId(featureId);
            String defValue = featureInfoVo.getDefValue();
            linkFbFeature.setFeatureItem(defValue);
            linkFbFeature.setCompanyId(companyId);
            linkFbFeature.setItemId(id);
            linkFbFeature.setEnable(CusConstants.ENABLE_Y_TYPE);
            cusLinkFbFeatureMapper.insert(linkFbFeature);
        }

        // 更新费用项信息
        LambdaQueryWrapper<CusFbFee> feeLambdaQueryWrapper = new LambdaQueryWrapper<>();
        feeLambdaQueryWrapper.eq(CusFbFee::getCompanyId,companyId);
        feeLambdaQueryWrapper.eq(CusFbFee::getId,id);

        CusFbFee fee = new CusFbFee();
        fee.setName(basicInfo.getName());
        fee.setUnit(basicInfo.getUnit());
        fee.setSuitableRange(basicInfo.getSuitableRange());
        fee.setContent(basicInfo.getContent());
        fee.setCalcRule(basicInfo.getCalcRule());
        return dmcFbFeeMapper.update(fee,feeLambdaQueryWrapper);
    }

    /**
     * 批量删除分包费用项
     *
     * @param ids 需要删除的分包费用项主键
     * @return 结果
     */
    @Override
    public int deleteDmcFbFeeByIds(String[] ids)
    {
        return dmcFbFeeMapper.deleteDmcFbFeeByIds(ids);
    }
    /**
     * 删除分包费用项信息
     *
     * @param id 分包费用项主键
     * @return 结果
     */
    @Override
    @Transactional
    public int deleteDmcFbFeeById(String id, Long companyId) {
        // 删除关联工序关系
        cusLinkFbGxMapper.delete(
                Wrappers.<CusLinkFbGx>lambdaQuery()
                .eq(CusLinkFbGx::getCompanyId,companyId)
                .eq(CusLinkFbGx::getFbId,id)
        );
        // 删除自己
        dmcFbFeeMapper.delete(
                Wrappers.<CusFbFee>lambdaQuery()
                .eq(CusFbFee::getId,id)
                .eq(CusFbFee::getCompanyId,companyId)
        );
        return 1;
    }

    private Long checkZxId(String zxId,Long companyId) {
        Long aLong = cusLinkFbGxMapper.selectCount(
                Wrappers.<CusLinkFbGx>lambdaQuery()
                        .eq(CusLinkFbGx::getCompanyId, companyId)
                        .eq(CusLinkFbGx::getGxId, zxId)
                .eq(CusLinkFbGx::getSort,'1')
        );
        return aLong;
    }


    @Override
    @Transactional
    public int insertFbFee(SubContVo vo, Long companyId) {
        String chapterId = vo.getChapterId();
        CusFbChapter chapter = cusFbChapterMapper.selectOne(
                Wrappers.<CusFbChapter>lambdaQuery()
                        .eq(CusFbChapter::getId, chapterId)
                        .eq(CusFbChapter::getCompanyId, companyId)
        );

        GxInfoVo gxInfo = vo.getGxInfo();

        String gxIds = gxInfo.getGxIds();

        List<String> gxIdList = StrUtil.split(gxIds, ",");
        String zxId = gxInfo.getZxId();

        if (checkZxId(zxId,companyId) > 0) {
            throw new ServiceException("主项已被使用!");
        }

        List<CusGxFee> gxFees = cusGxFeeMapper.selectList(
                Wrappers.<CusGxFee>lambdaQuery()
                        .eq(CusGxFee::getCompanyId, companyId)
                        .in(CusGxFee::getId, gxIdList)
        );

        Map<String, CusGxFee> gxFeeMap = gxFees.stream()
                .collect(Collectors.toMap(CusGxFee::getId, Function.identity(), (v1, v2) -> v2));

        CusFbFee fbFee = new CusFbFee();

        CusGxFee zxGx = gxFeeMap.get(zxId);

        // 设置基础信息
        fbFee.setName(zxGx.getName());
        fbFee.setUnit(zxGx.getUnit());
        fbFee.setCompanyId(companyId);
        fbFee.setChapterId(chapterId);
        String content = gxFees.stream().map(CusGxFee::getContent).collect(Collectors.joining(";"));
        fbFee.setContent(content);
        fbFee.setCalcRule(zxGx.getCalcRule());
        String gzfwmx = gxFees.stream().map(CusGxFee::getSuitableRange).collect(Collectors.joining(";"));
        fbFee.setSuitableRange(gzfwmx);
        fbFee.setOrderNum(getMaxOrderNun(chapterId,companyId) + 1);
        fbFee.setSpecId(chapter.getSpecId());
        dmcFbFeeMapper.insert(fbFee);

        String feeId = fbFee.getId();

        // 拉取特征  并保存
        List<CusLinkFeature> linkFeatures = cusLinkFeatureMapper.selectList(
                Wrappers.<CusLinkFeature>lambdaQuery()
                        .eq(CusLinkFeature::getCompanyId, companyId)
                        .in(CusLinkFeature::getItemId, gxIdList)
                        .eq(CusLinkFeature::getType, CusConstants.GB_TYPE)
        );


        List<CusLinkFeature> subjectFeatureList = linkFeatures.stream()
                .filter(e -> zxId.equals(e.getItemId()))
                .collect(Collectors.toList());


        List<String> featureIds = subjectFeatureList.stream().map(CusLinkFeature::getFeatureId).collect(Collectors.toList());
        linkFeatures.removeIf(next -> featureIds.contains(next.getFeatureId()));

        List<CusLinkFeature> mergeFeatureList = new ArrayList<>();
        Set<String> existIds = new HashSet<>();
        for (CusLinkFeature linkFeature : linkFeatures) {
            String featureId = linkFeature.getFeatureId();
            if (!existIds.contains(featureId)) {
                existIds.add(featureId);
                mergeFeatureList.add(linkFeature);
            }
        }
        subjectFeatureList.addAll(mergeFeatureList);
        for (CusLinkFeature cusLinkFeature : subjectFeatureList) {
            CusLinkFbFeature linkFbFeature = new CusLinkFbFeature();
            linkFbFeature.setFeatureId(cusLinkFeature.getFeatureId());
            linkFbFeature.setFeatureItem(cusLinkFeature.getFeatureItem());
            linkFbFeature.setItemId(feeId);
            linkFbFeature.setCompanyId(companyId);
            linkFbFeature.setEnable(CusConstants.OPERATION_Y_TYPE);
            cusLinkFbFeatureMapper.insert(linkFbFeature);
        }
        // 保存关联
        for (String gxId : gxIdList) {
            CusLinkFbGx fbGx = new CusLinkFbGx();
            fbGx.setCompanyId(companyId);
            fbGx.setFbId(feeId);
            fbGx.setGxId(gxId);
            fbGx.setEnable(CusConstants.ENABLE_Y_TYPE);
            cusLinkFbGxMapper.insert(fbGx);
        }
        return 1;
    }

    @Override
    public MergeGxToFeeResultBo changeGxLink(ChangeGxLinkVo vo,Long companyId) {
        List<GxIdAndLinkIdVo> newGx = vo.getNewGx();

        List<String> newGxIds = newGx.stream().map(GxIdAndLinkIdVo::getGxId).collect(Collectors.toList());
        Optional<String> first = newGx.stream().filter(e -> CusConstants.SUBJECT_TYPE.equals(e.getSubject())).map(GxIdAndLinkIdVo::getGxId).findFirst();
        String zxId = null;
        if (first.isPresent()) {
            zxId = first.get();
        }
        if (zxId == null) {
            throw new ServiceException("数据错误!");
        }

        List<CusGxFee> gxFees = cusGxFeeMapper.selectList(
                Wrappers.<CusGxFee>lambdaQuery()
                        .eq(CusGxFee::getCompanyId, companyId)
                        .in(CusGxFee::getId, newGxIds)
        );
        String gzfwmx = gxFees.stream().map(CusGxFee::getSuitableRange).collect(Collectors.joining(";"));

        MergeGxToFeeResultBo resultBo = new MergeGxToFeeResultBo();
        resultBo.setSuitableRange(gzfwmx);

        // 拉取特征
        List<CusLinkFeature> linkFeatures = cusLinkFeatureMapper.selectList(
                Wrappers.<CusLinkFeature>lambdaQuery()
                        .eq(CusLinkFeature::getCompanyId, companyId)
                        .in(CusLinkFeature::getItemId, newGxIds)
                        .eq(CusLinkFeature::getType, CusConstants.GB_TYPE)
        );

        Map<String, CusGxFee> gxFeeMap = gxFees.stream()
                .collect(Collectors.toMap(CusGxFee::getId, Function.identity(), (v1, v2) -> v2));

        String finalZxId = zxId;
        List<CusLinkFeature> subjectFeatureList = linkFeatures.stream()
                .filter(e -> finalZxId.equals(e.getItemId()))
                .collect(Collectors.toList());


        Set<String> existFeatureIds = subjectFeatureList.stream().map(CusLinkFeature::getFeatureId).collect(Collectors.toSet());
        linkFeatures.removeIf(next -> existFeatureIds.contains(next.getFeatureId()));


        List<CusLinkFeature> mergeFeatureList = new ArrayList<>();
        Map<String,CusLinkFeature> featureExistMap = new HashMap<>();

        for (CusLinkFeature linkFeature : linkFeatures) {
            String featureId = linkFeature.getFeatureId();
            if (!featureExistMap.containsKey(featureId)) {
                featureExistMap.put(featureId,linkFeature);
                mergeFeatureList.add(linkFeature);
            }else {
                CusLinkFeature cusLinkFeature = featureExistMap.get(featureId);
                cusLinkFeature.setFeatureItem("");
            }
        }
        subjectFeatureList.addAll(mergeFeatureList);
        Set<String> featureIds = subjectFeatureList.stream().map(CusLinkFeature::getFeatureId).collect(Collectors.toSet());

        if (featureIds.size() > 0) {
            List<CusFeature> cusFeatures = cusFeatureMapper.selectList(
                    Wrappers.<CusFeature>lambdaQuery().eq(CusFeature::getCompanyId, companyId).in(CusFeature::getId, featureIds)
            );

            Map<String, CusFeature> featureMap = cusFeatures.stream().collect(Collectors.toMap(CusFeature::getId, Function.identity()));

            List<FeatureRes> featureRes = new ArrayList<>();

            for (CusLinkFeature cusLinkFeature : subjectFeatureList) {
                FeatureRes res = new FeatureRes();
                String featureId = cusLinkFeature.getFeatureId();
                CusFeature cusFeature = featureMap.get(featureId);
                res.setLinkId(cusLinkFeature.getId());
                res.setFeatureId(featureId);
                res.setFeatureName(cusFeature.getFeatureName());
                res.setItems(StrUtil.split(cusFeature.getFeatureValues(), "|"));
                res.setInputEntry(cusFeature.getIsInput());
                res.setDefValue(cusLinkFeature.getFeatureItem());
                featureRes.add(res);
            }
            resultBo.setFeatureResList(featureRes);
        }

        // 材机分类
        String[] gxIds = newGxIds.toArray(new String[newGxIds.size()]);
        List<CusCategoryBo> cusCategoryBos = cusExpenseCategoriesMapper.selectGxFbLinkDataAndEntity(companyId,gxIds);

        List<CJFlRes> cjFlRes = new ArrayList<>();
        gxFeeMap.forEach((k,v) -> {
            List<CusCategoryBo> collect = cusCategoryBos.stream().filter(e -> k.equals(e.getSubpkId())).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(collect)) {
                for (CusCategoryBo cusCategoryBo : collect) {
                    CJFlRes cjfl = new CJFlRes();
                    cjfl.setName(v.getName() + "-" + cusCategoryBo.getCategoriesName());
                    cjfl.setUnit(cusCategoryBo.getUnit());
                    cjfl.setSpec(cusCategoryBo.getSpec());
                    cjfl.setType(cusCategoryBo.getType());
                    cjfl.setConsumption(cusCategoryBo.getConsumption());
                    cjFlRes.add(cjfl);
                }
            }
        });
        resultBo.setCjflList(cjFlRes);
        return resultBo;
    }


    @Override
    public int moveFeeToNewChapter(String chapterId, String[] ids, Long companyId) {
        dmcFbFeeMapper.moveFeeToNewChapter(chapterId,ids,companyId);
        return 1;
    }

    @Override
    public int insertFbFeeBySubject(AddSubjectContVo vo, Long companyId) {
        String subjectGxId = vo.getSubjectGxId();
        String topId = vo.getTopId();
        String chapterId = vo.getChapterId();
        CusFbChapter cusFbChapter = cusFbChapterMapper.selectOne(new LambdaQueryWrapper<CusFbChapter>().eq(CusFbChapter::getCompanyId, companyId).eq(CusFbChapter::getId, chapterId));
        if(!StringUtils.equals(cusFbChapter.getSpecId(),topId)){
            throw new ServiceException("请刷新页面重试,如多次未解决,请联系管理员!");
        }
        String versionId = vo.getVersionId();
        if (checkZxId(subjectGxId,companyId) > 0) {
            throw new ServiceException("主项已被使用!");
        }
        StaGxFee gxFee = staGxFeeMapper.selectOne(
                Wrappers.<StaGxFee>lambdaQuery()
                        .eq(StaGxFee::getId, subjectGxId)
                        .eq(StaGxFee::getVersionId, versionId)
        );
        if (gxFee != null) {
            CusFbFee fee = new CusFbFee();
            // 基础信息
            fee.setChapterId(chapterId);
            fee.setCompanyId(companyId);
            fee.setName(gxFee.getName());
            fee.setUnit(gxFee.getUnit());
            fee.setContent("{\"gygx\":[],\"qtnr\":[],\"bcnr\":[]}");
            fee.setCalcRule(gxFee.getCalcRule());
            fee.setSuitableRange("");
            fee.setOrderNum(getMaxOrderNun(chapterId,companyId) + 1);
            fee.setSpecId(topId);
            fee.setCode(null);
            this.save(fee);

            CusLinkFbGx cusLinkFbGx = new CusLinkFbGx();
            cusLinkFbGx.setGxId(subjectGxId);
            cusLinkFbGx.setCompanyId(companyId);
            cusLinkFbGx.setFbId(fee.getId());
            cusLinkFbGx.setEnable("Y");
            cusLinkFbGx.setSort(1);
            cusLinkFbGxMapper.insert(cusLinkFbGx);
        }
        return 1;
    }

    @Override
    @Transactional
    public int updateFbFee(FbUpdateVo vo, Long companyId) {
        //
        BasicInfoVo basicInfo = vo.getBasicInfo();
        String fbId = basicInfo.getId();
        List<String> delGxIds = vo.getDelGxIds();
        List<String> pxGxIds = vo.getPxGxIds();

        // 删除关联的工序
        if (CollUtil.isNotEmpty(delGxIds)) {
            cusLinkFbGxMapper.delete(
                    Wrappers.<CusLinkFbGx>lambdaQuery()
                            .eq(CusLinkFbGx::getCompanyId, companyId)
                            .in(CusLinkFbGx::getGxId, delGxIds)
                            .eq(CusLinkFbGx::getFbId, fbId)
            );
        }
        // 更新工序的顺序

        if (CollUtil.isNotEmpty(pxGxIds)) {
            List<Map<String,Object>> sortMapList = new ArrayList<>();

            for (int i = 0; i < pxGxIds.size(); i++) {
                Map<String,Object> sortMap = new HashMap<>();
                String s = pxGxIds.get(i);
                sortMap.put("gxId",s);
                sortMap.put("gxSort",i+1);
                sortMapList.add(sortMap);
            }
            cusLinkFbGxMapper.updateSort(sortMapList,fbId,companyId);
        }

        // 更新费用项信息
        LambdaQueryWrapper<CusFbFee> feeLambdaQueryWrapper = new LambdaQueryWrapper<>();
        feeLambdaQueryWrapper.eq(CusFbFee::getCompanyId,companyId);
        feeLambdaQueryWrapper.eq(CusFbFee::getId,fbId);
        CusFbFee fee = new CusFbFee();
        fee.setCode(basicInfo.getCode());
        fee.setName(basicInfo.getName());
        fee.setUnit(basicInfo.getUnit());
        fee.setOrderNum(basicInfo.getOrderNum());

        CusFeeContentParseBo feeContentParseBo = new CusFeeContentParseBo();
        feeContentParseBo.setBcnr(basicInfo.getBcnrContent());
        fee.setContent(JSON.toJSONString(feeContentParseBo));

        fee.setCalcRule(basicInfo.getCalcRule());
        return dmcFbFeeMapper.update(fee,feeLambdaQueryWrapper);
    }


    private Integer getMaxOrderNun(String chapterId,Long companyId) {
       return dmcFbFeeMapper.getMaxOrderNun(chapterId,companyId);
    }


    private CusFbFee getById(String id,Long companyId) {
        return dmcFbFeeMapper.selectOne(Wrappers.<CusFbFee>lambdaQuery()
                .eq(CusFbFee::getCompanyId,companyId)
                .eq(CusFbFee::getId,id));
    }

    /**
     * 重新编码
     * @param companyId
     * @return
     */
    @Override
    @Transactional
    public int rewriteCode(CusRewriteCodeRequest codeRequest) {
        Long companyId = SecurityUtils.getCompanyId();
        String specId = codeRequest.getSpecId();
        int countNotAllot = dmcFbFeeMapper.countNotAllot(companyId,specId, CusConstants.CHAPTER_ID_NULL);
        if (countNotAllot != 0) {
            throw new RuntimeException("存在未分配章节的费用项");
        }
        Integer suffixLen = codeRequest.getSuffixLen();
        Integer maxCountLen = dmcFbFeeMapper.countByChapterId(companyId,specId);
        if(suffixLen < maxCountLen){
            throw new RuntimeException("根据费用项数量统计,编码后缀不能少于" + maxCountLen + "位");
        }
        dmcFbFeeMapper.recodeFb(companyId,specId, codeRequest.getPrefix(),suffixLen);
        return 1;
    }

    @Override
    public List<CusFbFee> validateCode(Long companyId,String specId) {
        int countNotAllot = dmcFbFeeMapper.countNotAllot(companyId,specId, CusConstants.CHAPTER_ID_NULL);
        if (countNotAllot != 0) {
            throw new RuntimeException("存在未分配章节的费用项");
        }
        List<CusFbFee> cusFbFeeItems = new ArrayList<>();
        LambdaQueryWrapper<CusFbFee> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CusFbFee::getCompanyId, companyId);
        wrapper.eq(CusFbFee::getSpecId, specId);
        wrapper.groupBy(CusFbFee::getCode);
        wrapper.having("count(*) > 1 or `code`='' or ISNULL(`code`)");
        cusFbFeeItems = dmcFbFeeMapper.selectList(wrapper);
        return cusFbFeeItems;
    }

    @Override
    public StaFbFee getStaFbFeeById(String id, String specId, Long companyId) {
        String newestId = staVersionMapper.getNewestId(companyId,CusConstants.FB_TYPE,specId);
        return staFbFeeMapper.selectStaFbFeeById(newestId, id);
    }
}
